package cn.it.sqlSession;

import cn.it.executor.Exector;
import cn.it.executor.SimpleExecutor;
import cn.it.pojo.Configuration;

import java.lang.reflect.*;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    private Exector exector;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
        this.exector = new SimpleExecutor();
    }


    @Override
    public <E> List<E> selectList(String statementId, Object param) throws Exception {
        return (List<E>) exector.query(configuration, configuration.getMap().get(statementId), param);
    }

    @Override
    public <T> T selectOne(String statementId, Object param) throws Exception {
        List<Object> list = this.selectList(statementId, param);
        if (list != null && list.size() == 1) {
            return (T) list.get(0);
        }
        throw new RuntimeException("Error query ... ");
    }

    @Override
    public int save(String statementId, Object param) throws Exception {
        return common(statementId, param);
    }

    @Override
    public int update(String statementId, Object param) throws Exception {
        return common(statementId, param);
    }

    @Override
    public int delete(String statementId, Object param) throws Exception {
        return common(statementId, param);
    }

    private int common(String statementId, Object param) throws Exception {
        return exector.update(configuration, configuration.getMap().get(statementId), param);
    }

    @Override
    public <T> T getMapper(Class<?> Type) {

        Object newProxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{Type}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String statementId = className + "." + methodName;

                java.lang.reflect.Type returnType = method.getGenericReturnType();
                if (returnType == int.class) {
                    return common(statementId, args == null ? null : args[0]);
                } else if (returnType instanceof ParameterizedType) {
                    return selectList(statementId, args == null ? null : args[0]);
                }
                return selectOne(statementId, args == null ? null : args[0]);
            }
        });

        return (T) newProxyInstance;
    }
}
